Constructive solid geometry (CSG) nodes let us use boolean operations to create exciting shapes to prototype 3D levels and props directly in the editor.
For example, we can use a with three sides to create an extrusion of a regular triangle:
Or, we can use ’s Cone property to generate a cone:
By altering these properties, we can create many interesting shapes to use in prototype levels:
After we finish prototyping, we can export our scene as glTF for further development in external 3D modeling software. This feature is new in Godot v3.4.
Given these limitations, we prepared a couple of demos to showcase CSG nodes and their practical uses. In this tutorial, you’ll learn:
In addition, we cover recommendations and tips for helping you get the most out of these nodes.
Contents:
The primary purpose of CSG nodes is to combine them to make interesting shapes. However, nothing stops us from just using them for their easy customization.
Keeping your CSG trees shallow is highly advisable as Godot generates CSG meshes procedurally. This process is resource-intensive and not designed for real-time updates.
Among all the CSG nodes, two stand out:
These nodes make it easy for us to customize them in the 3D viewport through mouse interaction; an option that doesn’t provide.
All CSG nodes inherit from the CSGShape class. This
class holds the common properties for CSG nodes, including .
We can set the Operation property to one of three regular boolean operations:
This property works by processing the child nodes and their operations in tree order and applying them to itself.
Here’s a showcase of these operations:
The image above is a result of a basic scene structure with a node as a parent with two nodes as children:
Each column showcases the result of setting both nodes Operation property to Union, Intersection, and Subtraction. The CSGBox Operation property is only relevant if it’s a child of another CSG node.
The CSGShape’s Snap property makes meshes snap
to a given distance so that the faces of two meshes align precisely for
the boolean operations.
The Calculate Tangents property is only relevant for the root shape. This property is on by default. It allows for the use of normal maps.
The Use Collision property appears in the Inspector on the top-most CSG node. If true, this property informs Godot to calculate a collision shape for the physics engine based on the resulting CSG mesh. This shape acts as a static body and is active even if the CSG node’s visibility is off. Switching on this property results expands the Inspector with additional options for selecting the collision layer and mask:
One inheritance step below CSGShape is
CSGPrimitive. This is a parent class for all CSG nodes that
generate geometries. All CSG nodes except have this property.
We go over using this property when appropriate while showcasing each CSG node.
Most CSG nodes share the Smooth Faces property. We can find
it on , , , and CSGTorous.
This property blends between adjacent faces based on their normals with
this property turned on. We can see the effect of this setting better on
a . In the following image, we
have Smooth Faces turned off on the left and turned on to the
right:
The blending gives the right shape a rounder look, even though both images have the same geometry.
The Material property appears on all CSG nodes other
than , which doesn’t hold a
mesh. With this property, we can assign custom or resources, just like we would with a
. The difference with a is that we don’t control UVs
on CSG nodes.
Given that Godot generates the UVs for us, we can turn on the ’s Uv1 -> Triplanar mapping setting. In short, triplanar mapping projects a texture onto the mesh from three different angles and attempts to blend them to reduce apparent seams.
We use the node and a test texture for this presentation:
We have a scene with three nodes as follows:
We control the triplanar mapping using the Inspector settings under the ’s Uv 1 section: Scale, Offset, and Triplanar Sharpness which modifies the blending between faces.
A useful option on Flags -> World Triplanar. This option makes triplanar mapping work in world coordinates rather than local coordinates.
The World Triplanar option makes the projection planes align with the global world coordinates rather than the local ones. We can understand this better by viewing the following image:
The left cylinder keeps the texture aligned with its local transform because we haven’t turned on World Triplanar, unlike the one to the right.
That was a quick overview of how CSG nodes support resources. However, you may not need advanced setups like these for fast prototypes.
For an in-depth look at shaders, we recommend our Shader Secrets: Learn to Code 2D and 3D Shaders in Godot course:
From Godot v3.4, you can now export your mesh to external 3D programs using the glTF file format. It allows you to prototype environments in Godot and later refine them in another program like Blender.
To export your scene as glTF, click on Project -> Tools -> Export GLTF….
We grouped all CSG nodes in this guide as they all work together. In this section, we look at what each node does.
The node gives us a customizable box mesh.
We can control its properties in the Inspector:
Or, we can control it through the viewport, where the handles are a visual aid for the Width, Height, and Depth settings:
The Invert Faces property, inherited from
CSGPrimitive, is useful for creating volumes that we can
see inside of:
This screen capture shows the before and after turning on Invert Faces. Initially, the box looks solid, but after turning on Invert Faces, we see inside of it.
This effect happens because the default assigned to these nodes has Parameters -> Cull Mode set to Back.
If we set Cull Mode to Front, the inverse effect would happen, and we’d see inside the box when turning off Invert Faces.
The last option for disabling Cull Mode renders the box solid, regardless the Invert Faces property.
The node gives us more than cylinders to work with, depending on how many Sides we set and if we turn on the Cone property.
We can manipulate it in the 3D viewport with the help of the handles:
Or directly from the Inspector:
The minimum amount of sides is three.
The Cone property gives us a cone-shaped mesh. The Radius property applies to the larger side. Here are a few variations that this node can give us:
The node gives us the ability to combine custom meshes imported from external 3D software:
We need an *.obj file for assigning it to the property:
There are a few requirements for the mesh to work properly:
This custom mesh example meets all these requirements:
We look at this custom mesh more in the level prototyping demo.
The node lets us define a polygon figure in the XY plane that we can use in three modes: Depth, Spin, and Path.
We can construct the polygon manually in the Inspector through the Polygon property, with a minimum of three points:
Another option is to construct the XY polygon in the 3D viewport using visual tools.
We can create points with CTRL + Left Click and drag them to new positions.
The created polygon snaps automatically to the XY plane.
In Mode -> Depth, we can use the Depth property to extrude the polygon along the Z-axis:
Here’s a visual presentation of what customizing the polygon looks like with Mode -> Spin:
This mode gives us a different set of properties to adjust the constructed object:
We have a Spin Degree option that sets the amount of
rotation the polygon makes around the Y-axis. Here’s an example with
Spin Degree set to 140:
Spin Sides defines how many sides we generate during the spin process. A lower value results in a low-poly spin, while a higher value gives us more geometry.
Here’s an example of the above profile set to a Spin Sides
value of 32, instead of the default 8:
Next, we look at Mode -> Path. Again, we can use the same process of modifying the XY polygon visually.
We can tell Godot to extrude the profile along a curve defined through the node in this mode.
Setting the Mode -> Path updates the Inspector to reflect path-related options:
We must assign a node to the Path Node property since the node could be anywhere in the scene tree.
To have a smooth workflow with Mode -> Path, try keeping the profile centered around the node’s origin or within one of the quadrants while starting at the origin. This example showcases the two setups:
Following this recommendation, it’s a lot easier to predict the placement of the 3D extrusion.
Note that this doesn’t apply to Mode -> Spin since we might want to spin around the Y-axis at a distance:
The Path Interval Type property defines how Path Interval behaves. It can be set to either Distance or Subdivide. Path Interval defines the distance between extrusions.
We have two nodes using the same node that spans 2 units to
exemplify the differences. Both nodes have Path
Interval set to 0.5. The difference is that we set
Path Interval Type -> Distance on the left one, while the
right one to Path Interval Type -> Subdivide.
We can see how faces are extruded at intervals of 0.5
units in the left case while the right has 3 extrusions,
irrespective of the span.
Path Interval Type -> Distance is an absolute setting that makes extrude at regular intervals, while we use Path Interval Type -> Subdivide to set a given number of subdivisions instead.
When working with Path Interval Type -> Distance, try using the same value for ’s Curve -> Bake Interval property as ’s Path Interval. In most cases, this produces the best results.
In the following example, we keep the Bake Interval to its
default value of 0.2 and vary the Path Interval
going from left-to-right with these values: 0.1,
0.2, 0.5, 1.0.
Setting Path Interval to a lower value than Bake Interval doesn’t necessarily produce better results, so more resolution doesn’t mean better in this case. A lower resolution improves performance in heavy scenes.
The following property, Path Simplify Angle, lets us simplify the mesh by merging extrusions when the angle is smaller than the one set in the Inspector.
For example, we can see how this setting would greatly reduce the number of extrusions when dealing with long stretches of unchanging angles:
The Path Simplify Angle property is a massive help with performance.
Path Rotation has several modes:
Given that we don’t have control over the orientation, it might be difficult to get the desired result, so you’ll have to experiment with the settings:
Path Local lets us select the profile extrusion location. If Path Local is off, the extrusion happens on the curve. Otherwise, it starts relative to the location:
Path Continuous U and Path U Distance give us some control over how textures apply to the extrusions:
In this demonstration, we use the same test texture from before:
Note that in the extrusion to the left, each face takes the same UV square space, repeating the image with every extrusion step.
We have Path Continuous U turned on to the right, which repeats the image every meter by default. We can change this distance using the Path U Distance parameter.
Notice how the uses the texture. The texture’s top half gets mapped along the extrusions, while the bottom part gets cut in two halves and mapped to the caps.
Finally, we have the last -related property called Path Joined. It joins the caps of the :
The node is the simplest CSG mesh. It’s a sphere with one control point that updates the Radius.
Additionally, we can change the Radius from in the Inspector:
We also have additional settings:
The , or donut, has an inner and outer radius. We can change these through the visual handles or from the Inspector:
The Inner Radius and Outer Radius properties are conventions. The Inner Radius can be larger than the Outer Radius without any issues:
The other properties are:
The node is a special node
used to organize our scene. It doesn’t hold any mesh data itself. It
also doesn’t have any properties other than the ones inherited from
CSGShape:
To showcase how it works, we compare two setups with the same result, one of them with :
The two CSG trees under result in identical volumes. The one to the right is using .
The node can keep the CSG trees shallow to improve performance.
We look at a couple of examples of using the CSG nodes in practice for level prototyping and constructing walkable paths using the in combination with a node.
A distinct feature of these demos is that they have no code for CSG nodes specifically. Everything is in the 3D editor.
When constructing level prototypes, it’s essential to keep meshes as simple as possible because slow performance is the number one issue when working with CSG nodes.
This example showcases the creation of a level prototype by carving rooms with corridors inside a custom mesh.
To construct the interior of the mountain, we turn on ’s Invert Faces property so we can visualize the interior of the volume:
We can minimize the performance hit when working with CSG nodes by combining them into chunks as needed. For example, here we work under the node separately for constructing the bulk of the mountain carving:
Then, we make it a child of the node:
This brings us to our final carving result:
We also construct a few reusable components like a placeholder statue, decorative windows, and symbols:
Not all CSG trees combine through boolean operations. For example, the decorative window has this scene tree, with a node at the root:
Not performing the boolean operations results in better performance. Only use the boolean operations if necessary.
We need the boolean operations to construct the decorative symbol since we use it to carve inside the mountain as part of the room. This scene tree has a node for root to take advantage of the Subtraction boolean operator.
Once we are done laying out the rooms and corridors, we then add objects like ramps, stairs, and any other necessary parts:
Remember to turn on Use Collision for the required nodes to have the player and environment interact with one another:
Adding the other decorations gives us the final result:
This example showcases the use of in Path mode to create walkways between game islands in a 3D platformer type game:
Unlike the previous demo, where we use CSG nodes to combine them into more complex objects through boolean operations, we use to construct final objects for real-time use. We can do this because we aren’t using heavy boolean operators to combine objects.
We constructed a few islands using the GridMap node and connected them using path constructed with and nodes:
The objective is to get to the coin on the island on the far end of
the map. This requires that we construct walkways. We use a set to path mode, where both
the ’s Bake Interval and ’s Path Interval are
0.5 to get a reasonably smooth-looking geometry.
We use a Path Simplify Angle value of 1 to cut
down on the unnecessary geometry and set Path Rotation to
Path so that the walkways always have a flat top surface.
We have a custom material that repeats a seamless texture to integrate the paths with the GridMap visuals.
The texture image is a one-pixel vertical slice of this repeating pattern:
This creates repeating slices along the paths by having a repeated pattern along the X-axis. This axis is in the same direction as U in the context of shader terminology.
We get this final result for one of the walkways:
Remember to turn on Use Collision to get player-paths interaction:
For a thorough explanation on how to use the GridMap node, check out the GridMap guide.
This section lists a few recommendations that you might want to try when working with CSG nodes for a better development experience.
These aren’t hard rules, so try and experiment until you find a workflow that suits your style.
The 3D ground (XZ plane) divides into a one-by-one meters grid. You can turn on XY and YZ grids in the Editor -> Editor Settings… panel, along with other options related to the grid:
When designing profiles, it might be helpful to turn on the XY grid temporarily. This grid is represented by gray lines:
In some cases, it’s helpful to work in Orthogonal or Display Overdraw mode depending on the complexity of your scene. We find these visual modes in the viewport menu from the top-left corner.
The resulting materials for the holes come from the subtracted object when performing the subtraction operation.
For example, we subtract a small with a red material from a bigger with the default white material resulting in the hole becoming red:
When working in the spin mode, keep the profile in the positive X quadrant, that is, in the orange-shaded part of the axis.
Due to how Godot constructs the geometry in this mode, the boolean operations will fail if we don’t keep to the positive X quadrant:
In the following image, we can see how the Union operation produces bad geometry:
Instead, use rotation and translation to get the desired orientation, so Godot combines the objects correctly.
When constructing circular paths with in path mode, it isn’t enough to switch Path Joined on if the curve itself isn’t closed:
After closing the curve, you might have to massage the handles and end cap points slightly to get the desired result. At this point, it’s safe to turn on Path Joined to get the final geometry:
The Path Interval Property is clamped in the interval
[0, 1]. If for some reason, you want to go above
1, you can do so by:
Don’t go above 1 when working with Path Interval
Type -> Subdivide.
When working with Path Local turned off, make sure to keep
the location at
Vector3(0, 0, 0). This keeps the location around the world
origin. Otherwise, the translation factors into the location of the
final mesh, and it won’t align with the location of the :
You might expect to see the extrusion align with the node to the left, but it doesn’t because the location isn’t at the world origin, as you can see by checking the move gizmo.
When working with Path Rotation set to either Polygon or Path, make sure that the curve used for extrusion decreases along the Z-axis. Otherwise, we end up with an unusable mesh:
The one to the left has Path Rotation set to Polygon. The one on the right is set to Path.
When we check Up Vector -> Enabled, Godot calculates the orientation of the ’s Curve automatically for us.
When working with in path mode and Path Rotation set to PathFollow, remember to turn on Up Vector -> Enabled. Otherwise, the behaves as if Path Rotation is set to Path mode instead.
When working with the CSG nodes, parenting and moving the nodes around might result in visual artifacts in the 3D viewport.
If this happens to you, an easy fix is to save your scene first and click on Scene -> Reload Saved Scene from the menu, forcing the viewport to reset:
Be careful with this option. Save your changes first!